# -*- coding: utf-8 -*-
import tkinter,socketserver,threading,socket,os,base64,nls,datetime,time
import tkinter.font as tkFont
from tkinter.filedialog import askopenfilename
from tkinter.simpledialog import askstring
from playsound import playsound
from win32api import GetSystemMetrics

g_host_ip=''#本机服务IP.
g_default_port=8709#默认服务地址.
g_channel_port_li_c=[]#通道接口列表.client的list.
g_channel_temp_port_c=8710#通道起始接口.
g_channel_ip_li_s=[]#通道IP列表.server的list.
g_channel_port_li_s=[]#通道接口列表.

g_is_connected=False#是否已连接.涉及GUI和socket.
g_is_waitingroom=False#是否为候场室,若是,需播报语音.涉及GUI和socket.
g_o_buf=[]#待从连接发送的数据.涉及GUI和socket.
g_i_buf=[]#接收并显示的字符串.两秒钟刷新一次.

class MP3_Maker():#语音合成类.语音合成函数调用.
    def __init__(self,pt_file):
        self.__th=threading.Thread(target=self.__test_run)
        self.__test_file=pt_file
        self.state=True
        self.URL="wss://nls-gateway.cn-shanghai.aliyuncs.com/ws/v1"
        self.AKID="***"
        self.AKKEY="***"
        self.APPKEY="***"
    def start(self,text):
        self.__text=text
        self.__f=open(self.__test_file,"wb")
        self.__th.start()
    def test_on_data(self,data):
        self.__f.write(data)
    def test_on_close(self):
        self.__f.close()
        self.state=False
    def __test_run(self):
        tts=nls.NlsSpeechSynthesizer(
                url=self.URL,
                akid=self.AKID,
                aksecret=self.AKKEY,
                appkey=self.APPKEY,
                on_data=self.test_on_data,
                on_close=self.test_on_close
            )
        tts.start(self.__text,aformat="mp3")
def make_mp3(pt,text):#语音合成函数.TCP服务处理类中handle函数调用.
    nls.enableTrace(False)
    if not pt.endswith(".mp3"):
        pt=os.path.join(pt,text+".mp3")
    t=MP3_Maker(pt)
    t.start(text)
    temp=t.state
    while temp:#在此等待mp3制作完成.
        temp=t.state
    return(pt)
def make_and_play_mp3(pt,text):#在指定目录生成指定内容的mp3播放,并删除.
    pt=make_mp3("",text)
    playsound(pt)
    time.sleep(3)#切换线程.
    playsound(pt)
    if os.path.exists(pt):
      os.remove(pt)
    else:
      print("The %s does not exist."%pt)


def limit_str_len(stri,length=15):#限制字符长度.
    if(len(stri)>length):
        stri=stri[0:length]
    return(stri)
def set_window(x,y):#function to set the window to the x,y size, and in the middle. needed.
    screenwidth=GetSystemMetrics(0)#获取屏幕宽度大小像素.
    screenheight=GetSystemMetrics(1)#获取屏幕高度大小像素.
    size='%dx%d+%d+%d'%(x,y,(screenwidth-x)/2,(screenheight-y)/2)
    return(size)
def get_screen_size():#function to get the screen size. needed.
    return(GetSystemMetrics(0),GetSystemMetrics(1))#返回像素大小.

class My_GUI(tkinter.Frame):
    def __set_grid_unit_x_y(self):#set window size, base line and unit.
        (self.__x_unit,self.__y_unit)=get_screen_size()
        self.__x_unit/=self.UNIT_RATE#设置基础单元大小.
        self.__y_unit/=self.UNIT_RATE#设置基础单元大小.
        self.__x_unit_int=int(self.__x_unit)#基础单元大小取整.
        self.__y_unit_int=int(self.__y_unit)#基础单元大小取整.
    def __set_grid_num_x_y(self,x,y):#设置grid数量.
        self.__x_num=x
        self.__y_num=y
    def __create_frames(self):
        """Create the main window."""
        self.blank=[]
        for i in range(1,self.__x_num+1):
            for j in range(1,self.__y_num+1):
                c=tkinter.Frame(self,width=self.__x_unit_int,height=self.__y_unit_int,bg=self.BACK_COLOR)
                c.grid(row=j,column=i,sticky='WSEN')
                self.blank.append(c)
    def get_size(self):
        return(self.__x_unit_int*(self.__x_num),self.__y_unit_int*(self.__y_num))
    def __set_font(self):
        # self.ft=tkFont.Font(family='宋体',size=-int(self.__x_unit_int-10))#自动调整字体大小.
        self.ft=tkFont.Font(family='宋体',size=int((self.__y_unit-3)*1.2))#自动调整字体大小.
    def __set_button(self):
        self.__bsx=2
        self.__bsy=2
        self.__button_column=self.__x_num-self.__bsx+1
    def __get_button_column(self):
        return self.__button_column
    def __set_label(self):#set the label base size and base line.
        self.__lsx=6
        self.__lsy=2
        self.__label_column=self.__x_num-self.__lsx
    def __get_label_column(self):
        return self.__label_column
    def __set_entry(self):#set the entry base size and base line.
        self.__esx=6
        self.__esy=2
        self.__entry_column=self.__x_num-self.__lsx
    def __get_entry_column(self):
        return self.__entry_column

    def create_buttons(self):#Buttons.
        self.BUTTON0=tkinter.Button(self,height=1,bg=self.LABEL_COLOR_1,text="录入",command=self.process_entry_input,font=self.ft)
        self.BUTTON0.grid(row=1,column=self.__get_button_column(),rowspan=self.__bsy,columnspan=self.__bsx,sticky='WSEN')

        self.BUTTON1=tkinter.Button(self,height=1,bg=self.LABEL_COLOR_2,text="导入",command=self.open_file,font=self.ft)
        self.BUTTON1.grid(row=3,column=self.__get_button_column(),rowspan=self.__bsy,columnspan=self.__bsx,sticky='WSEN')

        self.BUTTON2=tkinter.Button(self,height=1,bg=self.LABEL_COLOR_1,text="播报",command=self.broadcast,font=self.ft)
        self.BUTTON2.grid(row=5,column=self.__get_button_column(),rowspan=self.__bsy,columnspan=self.__bsx,sticky='WSEN')

        self.BUTTON3=tkinter.Button(self,height=1,bg=self.LABEL_COLOR_2,text="重播",command=self.re_broadcast,font=self.ft)
        self.BUTTON3.grid(row=7,column=self.__get_button_column(),rowspan=self.__bsy,columnspan=self.__bsx,sticky='WSEN')

        self.BUTTON4=tkinter.Button(self,height=1,bg=self.LABEL_COLOR_1,text="设置",command=self.set_connection,font=self.ft)
        self.BUTTON4.grid(row=self.__y_num-6,column=self.__get_button_column(),rowspan=self.__bsy,columnspan=self.__bsx,sticky='WSEN')

        self.BUTTON5=tkinter.Button(self,height=1,bg=self.LABEL_COLOR_2,text="清空",command=self.clear,font=self.ft)
        self.BUTTON5.grid(row=self.__y_num-4,column=self.__get_button_column(),rowspan=self.__bsy,columnspan=self.__bsx,sticky='WSEN')

        self.BUTTON6=tkinter.Button(self,height=1,bg=self.LABEL_COLOR_1,text="删除",command=lambda:self.delete_item(self.LISTBOX_I),font=self.ft)
        self.BUTTON6.grid(row=15,column=self.__get_button_column()-11,rowspan=self.__bsy,columnspan=self.__bsx+1,sticky='WSEN')

        self.BUTTON7=tkinter.Button(self,height=1,bg=self.LABEL_COLOR_1,text="上移",command=lambda:self.move_up(self.LISTBOX_I),font=self.ft)
        self.BUTTON7.grid(row=9,column=self.__get_button_column()-11,rowspan=self.__bsy,columnspan=self.__bsx+1,sticky='WSEN')
        self.BUTTON8=tkinter.Button(self,height=1,bg=self.LABEL_COLOR_2,text="下移",command=lambda:self.move_down(self.LISTBOX_I),font=self.ft)
        self.BUTTON8.grid(row=11,column=self.__get_button_column()-11,rowspan=self.__bsy,columnspan=self.__bsx+1,sticky='WSEN')

        self.BUTTON9=tkinter.Button(self,height=1,bg=self.LABEL_COLOR_1,text="退出",command=self.quit,font=self.ft)
        self.BUTTON9.grid(row=self.__y_num-2,column=self.__get_button_column(),rowspan=self.__bsy,columnspan=self.__bsx,sticky='WSEN')

    def create_labels(self):#Labels.
        self.LABEL_OUT0=tkinter.Label(self,relief="raised",font=self.ft,height=1,bg=self.LABEL_COLOR_1,text="临时播报")
        self.LABEL_OUT0.grid(row=1,column=1,rowspan=self.__lsy,columnspan=self.__lsx,sticky='WSEN')

        self.LABEL_OUT1=tkinter.Label(self,relief="raised",font=self.ft,height=1,bg=self.LABEL_COLOR_2,text="源文件名")
        self.LABEL_OUT1.grid(row=3,column=1,rowspan=self.__lsy,columnspan=self.__lsx,sticky='WSEN')

        self.LABEL_OUT2=tkinter.Label(self,font=self.ft,height=1,bg=self.LABEL_COLOR_2,text="此处将显示导入文件名")
        self.LABEL_OUT2.grid(row=3,column=7,rowspan=self.__lsy,columnspan=self.__get_button_column()-1-6,sticky='WSEN')
        self.LABEL_OUT2.after(2000,self.display_recv_data)

        self.LABEL_OUT3=tkinter.Label(self,relief="raised",font=self.ft,height=1,bg=self.LABEL_COLOR_1,text="待播项目")
        self.LABEL_OUT3.grid(row=5,column=1,rowspan=self.__lsy,columnspan=self.__lsx,sticky='WSEN')

        """Output text on a fixed place, the title."""
        self.LABEL_OUT4=tkinter.Label(self,font=self.ft,height=1,bg=self.LABEL_COLOR_1,text="此处将显示待播放内容")
        self.LABEL_OUT4.grid(row=5,column=7,rowspan=self.__lsy,columnspan=self.__get_button_column()-1-6,sticky='WSEN')

        self.LABEL_OUT5=tkinter.Label(self,font=self.ft,height=1,bg=self.LABEL_COLOR_1,text="待\n播\n报\n\n名\n单")
        self.LABEL_OUT5.grid(row=7,column=1,rowspan=11,columnspan=1,sticky='WSEN')

        self.LABEL_OUT6=tkinter.Label(self,font=self.ft,height=1,bg=self.LABEL_COLOR_1,text="已\n播\n报\n\n名\n单")
        self.LABEL_OUT6.grid(row=7,column=12,rowspan=11,columnspan=1,sticky='WSEN')


        self.LABEL_OUT7=tkinter.Label(self,relief="raised",font=self.ft,height=1,bg=self.LABEL_COLOR_1,text="前导")
        self.LABEL_OUT7.grid(row=self.__y_num-2,column=1,rowspan=self.__lsy,columnspan=2,sticky='WSEN')
        self.LABEL_OUT8=tkinter.Label(self,relief="raised",font=self.ft,height=1,bg=self.LABEL_COLOR_1,text="后置")
        self.LABEL_OUT8.grid(row=self.__y_num-2,column=8,rowspan=self.__lsy,columnspan=2,sticky='WSEN')
    def change_label_text(self,u,string):
        u.config(text=string)

    def create_entrys(self):#Entries.
        """Get the keyboard input by entry."""
        self.ENTRY_IN=tkinter.Entry(self,font=self.ft,bg=self.INPUT_COLOR,relief="sunken")
        self.ENTRY_IN.grid(row=1,column=7,rowspan=self.__esy,columnspan=self.__get_button_column()-1-6,sticky='WSEN')
        self.contents_in=tkinter.StringVar()
        self.ENTRY_IN["textvariable"]=self.contents_in
        self.ENTRY_IN.bind('<Key-Return>',self.process_entry_input)
        self.ENTRY_IN.after(2000,self.notice_no_connection)
        self.ENTRY_LEADING=tkinter.Entry(self,font=self.ft,width=6,bg=self.INPUT_COLOR,relief="sunken")
        self.ENTRY_LEADING.grid(row=self.__y_num-2,column=3,rowspan=self.__esy,columnspan=5,sticky='WSEN')
        self.contents_leading=tkinter.StringVar()
        self.contents_leading.set('请')
        self.ENTRY_LEADING["textvariable"]=self.contents_leading

        self.ENTRY_ENDING=tkinter.Entry(self,font=self.ft,width=15,bg=self.INPUT_COLOR,relief="sunken")
        self.ENTRY_ENDING.grid(row=self.__y_num-2,column=10,rowspan=self.__esy,columnspan=9,sticky='WSEN')
        self.contents_ending=tkinter.StringVar()
        self.contents_ending.set('到三楼三幺七室候场')
        self.ENTRY_ENDING["textvariable"]=self.contents_ending
    def process_entry_input(self,event=None):
        """Enter bind callback. when there is an enter pressed in the entry, the function will be called."""
        self.IN=self.contents_in.get();
        self.IN_flag=True
        # print(self.IN)
        if self.IN in ['q','Q','quit','QUIT','exit','ESC']:
            self.quit()
        self.change_label_text(self.LABEL_OUT4,limit_str_len(self.IN))

    def create_scroll_listbox(self):#Listbox.
        #创建scrollbar,滚动条.
        self.SCROLLBAR_I=tkinter.Scrollbar(self,orient='vertical')
        self.SCROLLBAR_I.grid(row=7,column=7,rowspan=11,columnspan=1,sticky="WSEN")

        #创建listbox,列表框.并将其yscrollcommand绑定到scrollbar.set.
        self.LISTBOX_I=tkinter.Listbox(self,bg='black',fg='white',selectmode='single',height=6,width=13,yscrollcommand=self.SCROLLBAR_I.set)
        self.LISTBOX_I.bind('<ButtonRelease-1>',self.do_bind)#将释放按键事件绑定到do_bind函数.
        self.SCROLLBAR_I.config(command=self.LISTBOX_I.yview)#
        self.LISTBOX_I.grid(row=7,column=2,rowspan=11,columnspan=5,sticky='WSEN')

        #创建scrollbar,滚动条.
        self.SCROLLBAR_O=tkinter.Scrollbar(self,orient='vertical')
        self.SCROLLBAR_O.grid(row=7,column=18,rowspan=11,columnspan=1,sticky="WSEN")

        #创建listbox,列表框.并将其yscrollcommand绑定到scrollbar.set.
        self.LISTBOX_O=tkinter.Listbox(self,bg='black',fg='white',selectmode='single',height=6,width=13,yscrollcommand=self.SCROLLBAR_O.set)
        self.LISTBOX_O.bind('<ButtonRelease-1>',self.do_bind)#将释放按键事件绑定到do_bind函数.
        self.SCROLLBAR_O.config(command=self.LISTBOX_O.yview)#
        self.LISTBOX_O.grid(row=7,column=13,rowspan=11,columnspan=5,sticky='WSEN')
    def move_up(self,Listbox):
        """ Moves the item at position pos up by one """
        pos=Listbox.curselection()[0]
        if pos==0:
            return
        text=Listbox.get(pos)
        Listbox.delete(pos)
        Listbox.insert(pos-1,text)
        Listbox.selection_set(pos-1)
        self.change_label_text(self.LABEL_OUT4,limit_str_len(Listbox.get(0)))
    def move_down(self,Listbox):
        """ Moves the item at position pos up by one """
        pos=Listbox.curselection()[0]
        if pos==tkinter.END:
            return
        text=Listbox.get(pos)
        Listbox.delete(pos)
        Listbox.insert(pos+1,text)
        Listbox.selection_set(pos+1)
        self.change_label_text(self.LABEL_OUT4,limit_str_len(Listbox.get(0)))
    def delete_item(self,Listbox):
        """ Moves the item at position pos up by one """
        pos=Listbox.curselection()[0]
        Listbox.delete(pos)
        Listbox.selection_set(pos)
        self.change_label_text(self.LABEL_OUT4,limit_str_len(Listbox.get(0)))
    def do_bind(self,event):#listbox按键释放绑定函数.注意要传输event事件.此处原本设计判定选定的是哪个listbox.
        # self.change_label_text(self.LABEL_OUT4,limit_str_len(self.LISTBOX_I.get(self.LISTBOX_I.curselection())))
        # print(self.LISTBOX.get(self.LISTBOX.curselection()))
        pass

    def open_file(self):#打开播报列表,第一列,序号,第二列,名称.为播报内容.
        pt_full=askopenfilename(title="请选择播报单位列表",filetypes=[("text files","*.txt")])
        li_name=[]
        with open(pt_full,'r') as f:
            for line in f:
                temp=list(line.strip('\n').split(','))
                li_name.append(temp)
        self.LISTBOX_I.delete(0,tkinter.END)
        for t in li_name:
            self.LISTBOX_I.insert(tkinter.END,t)
        temp=os.path.basename(pt_full)
        if(len(temp)>=20):#如果文件名太长,则只取前十个字符.
            head=temp[0:8]
            tail=temp[-4:]
            temp=head+"..."+tail
        self.change_label_text(self.LABEL_OUT2,limit_str_len(temp))
        try:
            content=self.LISTBOX_I.get(0)
            content=content[0]
        except:
            content=""
        self.change_label_text(self.LABEL_OUT4,limit_str_len(content))

    def broadcast(self):#点击“播放”按钮绑定的函数.
        global g_is_waitingroom
        if(self.IN_flag):#有新输入的内容.
            content=self.IN
            if(content==""):
                pass
            else:
                self.IN_flag=False
                self.LISTBOX_O.insert(0,content)
                send_msg_to_waitingroom(content)#将新输入的内容发给候场室.
                self.sent_content=content
        else:#没有新输入的内容.
            try:
                content=self.LISTBOX_I.get(0)#从待播报列表获取播放内容.
                content=content[0]
                try:
                    content_next=self.LISTBOX_I.get(1)
                    content_next=content_next[0]
                except:
                    content_next=""
            except:
                content=""
            if(content==""):#待播报内容为空.
                pass
            else:
                self.LISTBOX_I.delete(0)
                self.LISTBOX_O.insert(0,content)
                b_content=self.contents_leading.get()+content+self.contents_ending.get()#加上前缀和后缀播放.
                if(content_next!=""):
                    b_content=b_content+"…请"+content_next+"做准备"
                if(g_is_waitingroom):#是候场室,直接播放.
                    make_and_play_mp3(r".",b_content.strip('\n').strip("\r"))#阻塞式播放.
                else:#非候场室,发送到候场室.
                    send_msg_to_waitingroom(b_content)
                self.sent_content=b_content
        try:
            content=self.LISTBOX_I.get(0)
            content=content[0]
        except:
            content=""
        self.change_label_text(self.LABEL_OUT4,limit_str_len(content))#设置待播放内容.

    def re_broadcast(self):#点击“重播”按钮绑定的函数.
        global g_is_waitingroom
        if(self.sent_content!=""):#如果已经播放内容不为空.
            self.LISTBOX_O.insert(0,self.sent_content)#将重播内容放入listbox.
            if(g_is_waitingroom):#是候场室,直接播放.
                make_and_play_mp3(r".",self.sent_content.strip('\n').strip("\r"))#阻塞式播放.
            else:#非候场室,发送到候场室.
                send_msg_to_waitingroom(self.sent_content)
        try:
            content=self.LISTBOX_I.get(0)
            content=content[0]
        except:
            content=""
        self.change_label_text(self.LABEL_OUT4,limit_str_len(content))#设置待播报项目内容.
    def set_connection(self):#设置连接对方IP,连接端口由对方给定.但不能确定是否能连通.
        global g_is_waitingroom,g_is_connected,g_host_ip,g_channel_ip_li_s
        try:#如果打开了设置框并输入了内容.
            if(len(g_channel_ip_li_s)!=0):
                result=askstring(title='设置待连接目标IP',
                                 prompt='格式:192.168.1.1(:0)\n括号内为选填内容,会议室可不填,默认为0.\n若设1,表明本机为候场室,将播放广播.\n若设0,表明本机为会议室,可发送叫号请求.',
                                 initialvalue="%s"%(g_channel_ip_li_s[-1]))#弹出设置对话框.显示本机IP.
            else:
                result=askstring(title='设置待连接目标IP',
                                 prompt='格式:192.168.1.1(:0)\n括号内为选填内容,会议室可不填,默认为0.\n若设1,表明本机为候场室,将播放广播.\n若设0,表明本机为会议室,可发送叫号请求.',
                                 initialvalue="%s"%(g_host_ip))#弹出设置对话框.显示本机IP.
            temp_s=result.split(":")[0]#从对话框获取连接IP.
            try:#如果输入了()内容.
                wt=result.split(":")[1]#判断自身是不是候场室.
                if(wt=="1"):#是候场室.
                    g_is_waitingroom=True
                    self.change_label_text(self.LABEL_OUT0,"候场室服务端")
                    self.change_label_text(self.LABEL_OUT1,"接收信息")
                    self.change_label_text(self.LABEL_OUT2,"接收信息")
                elif(wt=="0"):#不是候场室,是会议室.
                    g_is_waitingroom=False
                    self.change_label_text(self.LABEL_OUT0,"临时播报")
                    self.change_label_text(self.LABEL_OUT2,"此处将显示导入文件名")
                    self.contents_in.set("")
                    self.contents_in.set("")
                else:
                    self.contents_in.set("房间功能设置错误,请重新输入.")
            except:#如果没有输入()内容.仅输入IP.
                self.contents_in.set("")
            if(temp_s!=g_host_ip):#如果通道IP不是本机.
                reachable=ping_test(temp_s)#此函数不会报错.
                if(reachable==0):#可以ping通.向目标IP请求建立通道.
                    send_msg_to_server("请求建立连接",temp_s)#发送请求建立连接命令.
                else:#无法ping通.
                    self.contents_in.set("无法连接,请确认地址是否可达.")
        except:#打开对话框但退出了.
            pass

    def clear(self):
        """clear the output"""
        self.contents_in.set("")
        self.ENTRY_IN.delete('0',tkinter.END)
        self.change_label_text(self.LABEL_OUT2,"")
        self.change_label_text(self.LABEL_OUT4,"")
        self.LISTBOX_I.delete(0,tkinter.END)
        self.LISTBOX_O.delete(0,tkinter.END)

    def notice_no_connection(self):
        global g_is_connected
        temp="还未建立连接！请设置连接."
        temp_1=self.contents_in.get()
        if not g_is_connected:
            if(temp_1==temp):
                self.contents_in.set("")
            else:
                self.contents_in.set(temp)
        else:
            if(temp_1==temp):
                self.contents_in.set("")
        self.after(2000,self.notice_no_connection)

    def display_recv_data(self):
        global g_is_waitingroom,g_i_buf
        if g_is_waitingroom:#如果是候场室.
            if(len(g_i_buf)>0):#接收队列非空.
                self.change_label_text(self.LABEL_OUT2,limit_str_len(g_i_buf[0]))#将第一个单位放在"接收信息".
                next_unit=g_i_buf[0].split("…")#隔开的第二个单位..
                try:
                    self.change_label_text(self.LABEL_OUT4,limit_str_len(next_unit[1]))#将第二单位放在"待播项目".
                except:
                    self.change_label_text(self.LABEL_OUT4,"")
                self.LISTBOX_O.insert(0,next_unit[0])#在列表顶端显示已播放项目.
                # threading.Thread(target=make_and_play_mp3,args=(r".",str(g_i_buf[0]).strip('\n').strip("\r"))).start()#非阻塞式播放.
                self.sent_content=str(g_i_buf[0]).strip('\n').strip("\r")
                make_and_play_mp3(r".",self.sent_content)#阻塞式播放.
                del g_i_buf[0]#删除接收队列元素0.
        self.after(1000,self.display_recv_data)


    def __init__(self,master=None):
        global g_host_ip,g_default_port
        #界面颜色相关常量.
        self.INPUT_COLOR="#F0F0F0"
        self.BACK_COLOR="#CAE9FE"
        self.LABEL_COLOR_1="#E1F1FF"
        self.LABEL_COLOR_2="#B1DDFF"
        self.NUMBER=20#满屏是100.
        self.UNIT_RATE=75#设置成100,则单位像素大小为屏幕的100分之一.80或100.
        self.IN=''#value get from the entry_in.
        self.IN_flag=False
        self.sent_content=''

        g_host_ip=socket.gethostbyname(socket.gethostname())#获取本机的IP地址.
        g_default_port=8709

        tkinter.Frame.__init__(self,master)
        self.__set_grid_unit_x_y()
        self.__set_grid_num_x_y(self.NUMBER,self.NUMBER)
        self.grid()
        self.__create_frames()
        self.__set_font()
        self.__set_button()
        self.__set_label()
        self.__set_entry()
        self.create_buttons()
        self.create_labels()
        self.create_entrys()
        self.create_scroll_listbox()
        threading.Thread(target=run_hub).start()#开启路由服务.

def send_msg_to_waitingroom(text):#发送广播.
    global g_o_buf
    g_o_buf.append(text)

def parse(sock):#解析套接字接收到的内容,并设置发送内容.
    global g_o_buf,g_i_buf
    try:
        data=sock.recv(1024)
        info=sock.getpeername()
        if data !="":
            temp=data.decode()#解码获得的内容.
            g_i_buf.append(temp)#将接收到的数据存入g_i_buf.
            ticks=datetime.datetime.now().strftime('%m-%d %H:%M:%S')
            print("Time:{}      From:{}\n{}\n".format(ticks,info[0],temp))
    except:
        pass
    if(len(g_o_buf)>0):
        sock.send(g_o_buf[0].encode())
        del g_o_buf[0]

def create_pair_server(IP,PORT):#创建服务端服务.
    global g_is_connected,g_is_waitingroom
    server=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    server.bind((IP,PORT))
    server.listen(1) #接收的连接数1
    s,address=server.accept()#接收到连接.此处才是客户端真正的IP和port.
    s.setblocking(False)#非阻塞.
    print("已建立S端连接%s,%s"%(str(address[0]),str(address[1])))
    g_is_connected=True
    while True: #循环收发数据包,常连接,一定要连接建立了以后才会开启下面的循环.
        parse(s)
        time.sleep(1)#切换线程.
def create_pair_client(IP,PORT):#创建客户端服务.
    global g_is_connected,g_is_waitingroom
    client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    client.connect((IP,PORT))
    client.setblocking(False)#非阻塞.
    print("已建立C端连接%s,%s"%(IP,PORT))
    g_is_connected=True
    while True:
        parse(client)
        time.sleep(1)#切换线程.
def send_msg_to_server(o_buf,IP):#发送请求给目标IP,默认端口.
    global g_default_port,g_channel_ip_li_s,g_channel_port_li_s
    client=socket.socket(socket.AF_INET,socket.SOCK_STREAM)#创建套接字.
    client.connect((IP,g_default_port))#连接目标IP的默认端口,所有端口均开启此服务.
    client.send(o_buf.encode())#发送内容.
    i_buf=client.recv(1024)#接收内容.
    if i_buf:
        i_buf=i_buf.decode()
        if(i_buf.startswith("分配IP")):#请求建立连接后收到返回的IP和端口.此时可以用此端口建立连接.
            temp_ip=i_buf.split(":")[1]
            temp_port=int(i_buf.split(":")[2])
            threading.Thread(target=create_pair_client,args=(temp_ip,temp_port)).start()#建立连接C端.
            g_channel_ip_li_s.append(temp_ip)
            g_channel_port_li_s.append(temp_port)
        else:
            print(i_buf)
    client.close()
class HUB_handler(socketserver.BaseRequestHandler):#基础网络服务类.
    def handle(self):
        global g_channel_port_li_c,g_channel_temp_port_c
        self.data=self.request.recv(1024).strip()#获取信息.
        I_buf=bytes.decode(self.data)#将bytes转换为str.
        ticks=datetime.datetime.now().strftime('%m-%d %H:%M:%S')
        if(I_buf.startswith("请求建立连接")):#如果收到建立连接的请求.
            threading.Thread(target=create_pair_server,args=(g_host_ip,g_channel_temp_port_c)).start()#开启线程,建立一个连接S端.
            O_buf="分配IP:{}:{}".format(g_host_ip,g_channel_temp_port_c)#将IP和端口号发给对方.
            g_channel_port_li_c.append(g_channel_temp_port_c)
            g_channel_temp_port_c+=1#设置下一个端口号.
        else:
            O_buf="{} {} wrote:{}".format(self.client_address[0],ticks,I_buf)
            pass
        self.request.sendall(O_buf.encode())
def run_hub():#开启客户端默认服务.
    global g_host_ip,g_default_port
    server=socketserver.TCPServer((g_host_ip,g_default_port),HUB_handler)
    server.serve_forever()
def start_hub():#开启本机软件路由服务.
    threading.Thread(target=run_hub).start()

def ping_test(ip):#测试是否能够ping通.0为可以ping通,1为不能ping通.
    return(os.system('ping -n 2 -w 20 %s'%ip))#0 is ok, 1 is stuck.

def run_communicator():
    window=tkinter.Tk()
    window.title("局域网排队叫号系统")
    a=My_GUI(master=window)
    x,y=a.get_size()
    window.geometry(set_window(x,y))
    window.resizable(False,False)#窗口是否可以调整大小.
    window.attributes("-topmost",1)
    window.attributes("-topmost",0)
    a.mainloop()
    try:
        window.destroy()
    except:
        pass

if __name__=='__main__':
    run_communicator()